added samples
[windows-sources.git] / sdk / samples / all in on code / Visual Studio 2008 / CppCLINativeDllWrapper / ReadMe.txt
blob2c1dca448025bed45ea25c5bb0ff8f072eaec159
1 =============================================================================
2       DYNAMIC LINK LIBRARY : CppCLINativeDllWrapper Project Overview
3 =============================================================================
5 /////////////////////////////////////////////////////////////////////////////
6 Summary:
8 This C++/CLI code sample demonstrates making C++/CLI wrapper classes for a 
9 native C++ DLL module that allow you to call from any .NET code to the 
10 classes and functions exported by the module.
12   CSCallNativeDllWrapper/VBCallNativeDllWrapper (any .NET clients)
13           -->
14       CppCLINativeDllWrapper (this C++/CLI wrapper)
15               -->
16           CppDynamicLinkLibrary (a native C++ DLL module)
18 In this code sample, the CSimpleObjectWrapper class wraps the native C++ 
19 class CSimpleObject, and the NativeMethods class wraps the global functions 
20 exported by CppDynamicLinkLibrary.dll.
22 The interoperability features supported by Visual C++/CLI offer a particular 
23 advantage over other .NET languages when it comes to interoperating with 
24 native modules. Apart from the traditional explicit P/Invoke, C++/CLI allows 
25 implicit P/Invoke, also known as C++ Interop, or It Just Work (IJW), which 
26 mixes managed code and native code almost invisibly. The feature provides 
27 better type safety, easier coding, greater performance, and is more forgiving 
28 if the native API is modified. You can use the technology to build .NET 
29 wrappers for native C++ classes and functions if their source code is 
30 available, and allow any .NET clients to access the native C++ classes and 
31 functions through the wrappers.
34 /////////////////////////////////////////////////////////////////////////////
35 Sample Relation:
36 (The relationship between the current sample and the rest samples in 
37 Microsoft All-In-One Code Framework http://1code.codeplex.com)
39 CppCLINativeDllWrapper -> CppDynamicLinkLibrary
40 The C++/CLI sample module CppCLINativeDllWrapper wraps the classes and 
41 functions exported by the native C++ sample module CppDynamicLinkLibrary. The
42 wrapper classes and functions can be called by any .NET code to indirectly 
43 interoperate with the native C++ classes and functions.
46 /////////////////////////////////////////////////////////////////////////////
47 Implementation:
49 Step1. Create a Visual C++ / CLR / Class Library project named 
50 CppCLINativeDllWrapper in Visual Studio 2008. The project wizard generates 
51 a default empty C++/CLI class:
53     namespace CppCLINativeDllWrapper {
55             public ref class Class1
56             {
57                     // TODO: Add your methods for this class here.
58             };
59     }
61 Step2. Reference the native C++ DLL CppDynamicLinkLibrary.
63   Option1. Link the LIB file of the DLL by entering the LIB file name in 
64   Project Properties / Linker / Input / Additional Dependencies. We can 
65   configure the search path of the LIB file in Project Properties / Linker / 
66   General / Additional Library Directories.
68   Option2. Select References from the Project's shortcut menu. On the 
69   Property Pages dialog box, expand the Common Properties node, select 
70   References, and then select the Add New Reference... button. The Add 
71   Reference dialog box is displayed. This dialog lists all the libraries that 
72   you can reference. The Projects tab lists all the projects in the current 
73   solution and any libraries they contain. If the CppDynamicLinkLibrary 
74   project is in the current solution, select CppDynamicLinkLibrary and click 
75   OK in the Projects tab.
77 Step3. Including the header file that declares the functions and classes of 
78 the DLL.
80     #include "CppDynamicLinkLibrary.h"
82 You can configure the search path of the header file in Project Properties / 
83 C/C++ / General / Additional Include Directories.
85 Step4. Design the C++/CLI wrapper class CSimpleObjectWrapper for the native 
86 C++ class CSimpleObject.
88     public ref class CSimpleObjectWrapper
89     {
90     public:
91         CSimpleObjectWrapper(void);
92         virtual ~CSimpleObjectWrapper(void);
94         // Property
95         property float FloatProperty
96         {
97             float get(void);
98             void set(float value);
99         }
101         // Method
102         virtual String ^ ToString(void) override;
104         // Static method
105         static int GetStringLength(String ^ str);
107     protected:
108         !CSimpleObjectWrapper(void);
110     private:
111         CSimpleObject *m_impl;
112     };
114 The class wraps an instance of the native C++ class CSimpleObject. The 
115 instance is pointed by the private member variable m_impl. It is 
116 initialized in the constructor CSimpleObjectWrapper(void);, and is freed 
117 in the desctructor (virtual ~CSimpleObjectWrapper(void);) and the finalizer 
118 (!CSimpleObjectWrapper(void);).
120     CSimpleObjectWrapper::CSimpleObjectWrapper(void)
121     {
122         m_impl = new CSimpleObject();
123     }
124     
125     CSimpleObjectWrapper::~CSimpleObjectWrapper(void)
126     {
127         if (m_impl)
128         {
129             delete m_impl;
130             m_impl = NULL;
131         }
132     }
134     CSimpleObjectWrapper::!CSimpleObjectWrapper(void)
135     {
136         if (m_impl)
137         {
138             delete m_impl;
139             m_impl = NULL;
140         }
141     }
143 The public member properties and methods of CSimpleObjectWrapper wraps those 
144 of the native C++ class CSimpleObject. They redirects the calls to 
145 CSimpleObject through the CSimpleObject instance pointed by m_impl. Type 
146 marshaling takes place between the managed and native code.
148     float CSimpleObjectWrapper::FloatProperty::get(void)
149     {
150         return m_impl->get_FloatProperty();
151     }
153     void CSimpleObjectWrapper::FloatProperty::set(float value)
154     {
155         m_impl->set_FloatProperty(value);
156     }
158     String ^ CSimpleObjectWrapper::ToString(void)
159     {
160         wchar_t szStr[100];
161         HRESULT hr = m_impl->ToString(szStr, ARRAYSIZE(szStr));
162         if (FAILED(hr))
163         {
164             Marshal::ThrowExceptionForHR(hr);
165         }
166         // Marshal PWSTR to System::String and return it.
167         return gcnew String(szStr);
168     }
170     int CSimpleObjectWrapper::GetStringLength(System::String ^ str)
171     {
172         // Marshal System::String to PCWSTR, and call the C++ function.
173         marshal_context ^ context = gcnew marshal_context();
174         PCWSTR pszString = context->marshal_as<const wchar_t*>(str);
175         int length = CSimpleObject::GetStringLength(pszString);
176         delete context;
177         return length;
178     }
180 Step5. Design the C++/CLI wrapper class NativeMethods for the functions 
181 exported by the native C++ DLL module.
183     /// <summary>
184     /// Function delegate of the 'PFN_COMPARE' callback function. 
185     /// </summary>
186     /// <remarks>
187     /// The delegate type has the UnmanagedFunctionPointerAttribute. Using 
188     /// this attribute, you can specify the calling convention of the native 
189     /// function pointer type. In the native API's header file, the callback 
190     /// PFN_COMPARE is defined as __stdcall (CALLBACK), so here we specify 
191     /// CallingConvention::StdCall.
192     /// </remarks>
193     [UnmanagedFunctionPointer(CallingConvention::StdCall)]
194     public delegate int CompareCallback(int a, int b);
197     /// <summary>
198     /// This C++/CLI class wraps the functions exported by the native C++ 
199     /// module CppDynamicLinkLibrary.dll. 
200     /// </summary>
201     public ref class NativeMethods
202     {
203     public:
204         static int GetStringLength1(String ^ str);
205         static int GetStringLength2(String ^ str);
206         static int Max(int a, int b, CompareCallback ^ cmpFunc);
207     };
209 All methods in NativeMethods are declared as static for the global functions 
210 exported by CppDynamicLinkLibrary. They redirect calls to the native DLL.
212     int NativeMethods::GetStringLength1(String ^ str)
213     {
214         // Marshal System::String to PCWSTR, and call the C++ function.
215         marshal_context ^ context = gcnew marshal_context();
216         PCWSTR pszString = context->marshal_as<const wchar_t*>(str);
217         int length = ::GetStringLength1(pszString);
218         delete context;
219         return length;
220     }
222     int NativeMethods::GetStringLength2(String ^ str)
223     {
224         // Marshal System::String to PCWSTR, and call the C++ function.
225         marshal_context ^ context = gcnew marshal_context();
226         PCWSTR pszString = context->marshal_as<const wchar_t*>(str);
227         int length = ::GetStringLength2(pszString);
228         delete context;
229         return length;
230     }
232     int NativeMethods::Max(int a, int b, CompareCallback ^ cmpFunc)
233     {
234         // Convert the delegate to a function pointer.
235         IntPtr pCmpFunc = Marshal::GetFunctionPointerForDelegate(cmpFunc);
236         return ::Max(a, b, static_cast<::PFN_COMPARE>(pCmpFunc.ToPointer()));
237     }
240 /////////////////////////////////////////////////////////////////////////////
241 References:
243 Using C++ Interop (Implicit PInvoke)
244 http://msdn.microsoft.com/en-us/library/2x8kf7zx.aspx
246 How to: Wrap Native Class for Use by C#
247 http://msdn.microsoft.com/en-us/library/ms235281.aspx
250 /////////////////////////////////////////////////////////////////////////////